#include "../../includes/controller/ServidorAplicacao.h"

namespace controller
{
	ServidorAplicacao::ServidorAplicacao( const QString &ip, const unsigned short &porta, QObject *parent ):
		QTcpServer( parent ), porta( porta ),
		arquivosPath( "ArquivosPath" ), clientesPath( "ClientesPath/clientes.bin" )
	{

		QDir local("."), dirArquivos( arquivosPath ), dirClientes( "ClientesPath" );
		// Este trecho de codigo roda sobre a thread main...
		Logger::setOutput( stdout );
		console = new ThreadConsole( this, stdin, NULL );
		address = QHostAddress( ip );

		if( ! dirArquivos.exists() )
		{
			local.mkdir( dirArquivos.dirName() );
			dirArquivos.refresh();
		}

		if( ! dirClientes.exists() )
		{
			local.mkdir( dirClientes.dirName() );
			dirClientes.refresh();
		}

		try
		{
			servidorArquivos = new model::ServidorArquivos( arquivosPath, this );
			servidorClientes = new model::ServidorClientes( clientesPath );
		} catch ( QString *_m )
		{
			qDebug() << "Exception:" << *_m;
			delete _m;

			terminate();

			return;
		}

		Logger::write( QString("Base de arquivos montada em %1.").arg( dirArquivos.absolutePath() ) );
		Logger::write( QString("Base de clientes montada em %1.").arg( dirClientes.absolutePath() ) );
		Logger::write( "" );

		connect( console, SIGNAL( terminated() ), this, SLOT( terminate() ) );
	}

	void ServidorAplicacao::incomingConnection( int descriptor )
	{
		ThreadSessao *thread;

		Logger::write( "Nova conexao!" );

		thread = new ThreadSessao( this, descriptor, NULL );
		threads.append( thread );

        connect( thread, SIGNAL( terminado( ThreadSessao* ) ), this, SLOT( removerThread( ThreadSessao* ) ) );

		thread->start();
	}

	void ServidorAplicacao::removerThread( ThreadSessao* thread )
	{
		threads.removeOne( thread );
	}

	void ServidorAplicacao::iniciar()
	{
		Logger::write( QString("Escutando porta %1...").arg( porta ) );

		if( ! listen( address, porta ) )
		{
			QString *s;
			s = new QString();
			s->append( QString( "Erro ao escutar porta %1: %2." ).arg( porta ).arg( errorString() ) );
			throw s;
		}

		console->start();
	}

	void ServidorAplicacao::terminate()
	{
		close();

		delete console;

		servidorClientes->save();

		delete servidorClientes;
		delete servidorArquivos;

		console = NULL;
		servidorClientes = NULL;
		servidorArquivos = NULL;

		emit terminateApp();
	}

	ServidorAplicacao::~ServidorAplicacao()
	{
		if( console != NULL )
		{
			delete console;
		}

		if( servidorClientes != NULL )
		{
			servidorClientes->save();
			delete servidorClientes;
		}

		if( servidorArquivos != NULL )
		{
			delete servidorArquivos;
		}
	}

	void ServidorAplicacao::listaArquivosAbertosClientes()
	{
		servidorArquivos->listaArquivosAbertosClientes();
	}

	model::Arquivo* ServidorAplicacao::adicionarArquivoEvent( const QString& nome, const QByteArray &array )
	{
		return servidorArquivos->adicionarArquivo( nome, array );
	}

	bool ServidorAplicacao::fileExistsEvent( const QString &nome )
	{
		return servidorArquivos->fileExists( nome );
	}

	void ServidorAplicacao::apagarArquivoEvent( model::Arquivo *arquivo )
	{
		servidorArquivos->apagarArquivo( arquivo );
	}

	model::Arquivo* ServidorAplicacao::getArquivoEvent( const QString &nome, model::ModoAbertura &modo )
	{
		return servidorArquivos->getArquivo( nome, modo );
	}

	QList<model::Arquivo*>* ServidorAplicacao::getArquivoPorExtEvent( const QString &ext,
		const model::ModoAbertura &modo )
	{
		return servidorArquivos->getArquivoPorExt( ext, modo );
	}

	QList<QPair<QString, model::ModoAbertura> >* ServidorAplicacao::listarDiretorioEvent()
	{
		return servidorArquivos->listarDiretorio();
	}

	void ServidorAplicacao::renomearArquivoEvent( model::Arquivo *origem, const QString &destino )
	{
		servidorArquivos->renomearArquivo( origem, destino );
	}

	model::Cliente* ServidorAplicacao::getClienteEvent( const QString &nome )
	{
		return servidorClientes->getCliente( nome );
	}

	model::Cliente* ServidorAplicacao::cadastrarClienteEvent( const QString &nome )
	{
		return servidorClientes->cadastrarCliente( nome );
	}

	void ServidorAplicacao::logoutClienteEvent( model::Cliente *c )
	{
		servidorClientes->logoutCliente( c );
	}
}
